#include "hal_device.h"
#include "hal_sensor.h"
#include "stm32f4xx.h"
#include "stm32f4xx_ll_tim.h"
#include "stm32f4xx_ll_bus.h"
#include "stm32f4xx_ll_gpio.h"
#include "stm32f4xx_ll_adc.h"
#include "stm32f4xx_ll_dma.h"

void stm32_adc_delay(volatile int us)
{
	volatile int j;
	
	while(us--){
		for(j = 0;j < 1000;j++);
	}
}

struct stm32f4xx_adc_result_s{
	uint32_t ch[8];
};

static int stm32f4xx_adc_init(struct hal_dev_s *dev)
{
	struct stm32f4xx_adc_result_s *result = (struct stm32f4xx_adc_result_s *)dev->priv_data;
	
	LL_ADC_InitTypeDef ADC_InitStruct = {0};
	LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
	LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
	LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);
	
	/**ADC1 GPIO Configuration  
	PA3   ------> ADC1_IN3
	PA2   ------> ADC1_IN2 
	*/
	
	GPIO_InitStruct.Pin = LL_GPIO_PIN_3|LL_GPIO_PIN_2;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	ADC_InitStruct.Resolution         = LL_ADC_RESOLUTION_12B;
	ADC_InitStruct.DataAlignment      = LL_ADC_DATA_ALIGN_RIGHT;
	ADC_InitStruct.SequencersScanMode = LL_ADC_SEQ_SCAN_ENABLE;
	LL_ADC_Init(ADC1, &ADC_InitStruct);
	
	ADC_REG_InitStruct.TriggerSource    = LL_ADC_REG_TRIG_SOFTWARE;
	ADC_REG_InitStruct.SequencerLength  = LL_ADC_REG_SEQ_SCAN_ENABLE_2RANKS;
	ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
	ADC_REG_InitStruct.ContinuousMode   = LL_ADC_REG_CONV_CONTINUOUS;
	ADC_REG_InitStruct.DMATransfer      = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
	LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
	
	LL_ADC_REG_SetFlagEndOfConversion(ADC1, LL_ADC_REG_FLAG_EOC_SEQUENCE_CONV);
	LL_ADC_DisableIT_EOCS(ADC1);
	
	ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_SYNC_PCLK_DIV6;
	ADC_CommonInitStruct.Multimode   = LL_ADC_MULTI_INDEPENDENT;
	LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);

	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_2);
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_112CYCLES);
	
	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_3);
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_112CYCLES);

	LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_0, LL_DMA_CHANNEL_0);
	LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_STREAM_0, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
	LL_DMA_SetStreamPriorityLevel(DMA2, LL_DMA_STREAM_0, LL_DMA_PRIORITY_LOW);
	LL_DMA_SetMode(DMA2, LL_DMA_STREAM_0, LL_DMA_MODE_CIRCULAR);
	LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_STREAM_0, LL_DMA_PERIPH_NOINCREMENT);
	LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_STREAM_0, LL_DMA_MEMORY_INCREMENT);
	LL_DMA_SetPeriphSize(DMA2, LL_DMA_STREAM_0, LL_DMA_PDATAALIGN_WORD);
	LL_DMA_SetMemorySize(DMA2, LL_DMA_STREAM_0, LL_DMA_MDATAALIGN_WORD);
	LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_0);
	
	LL_DMA_SetDataLength(DMA2,LL_DMA_CHANNEL_0,2);
	LL_DMA_SetPeriphAddress(DMA2,LL_DMA_STREAM_0,LL_ADC_DMA_GetRegAddr(ADC1,LL_ADC_DMA_REG_REGULAR_DATA));
	LL_DMA_SetMemoryAddress(DMA2,LL_DMA_STREAM_0,(uint32_t)result->ch);
	
//	NVIC_SetPriority(DMA2_Stream0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),10, 0));
//	NVIC_EnableIRQ(DMA2_Stream0_IRQn);
	
	LL_DMA_EnableIT_TC(DMA2,LL_DMA_STREAM_0);

	return 0;
}

static int stm32f4xx_adc_open(struct hal_dev_s *dev,uint16_t flag)
{
	LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_0);
	LL_ADC_Enable(ADC1);
	
	stm32_adc_delay(1000);
	LL_ADC_REG_StartConversionSWStart(ADC1);
	
	return 0;
}

int32_t  stm32f4xx_adc_read(struct hal_dev_s *dev, void *buffer, int size,int pos)
{
	struct stm32f4xx_adc_result_s *result = (struct stm32f4xx_adc_result_s *)dev->priv_data;
	struct adc_report_s *report = (struct adc_report_s *)buffer;
	
	report->data[0] = (float)result->ch[0];
	report->data[1] = (float)result->ch[1];

	return size;
}

struct hal_dev_s stm32f4xx_adc_helicopter_dev;
struct stm32f4xx_adc_result_s adc_result;

int stm32f4xx_helicopter_adc_register(void)
{
	stm32f4xx_adc_helicopter_dev.init  = stm32f4xx_adc_init;
	stm32f4xx_adc_helicopter_dev.open  = stm32f4xx_adc_open;
	stm32f4xx_adc_helicopter_dev.read  = stm32f4xx_adc_read;
	stm32f4xx_adc_helicopter_dev.priv_data = &adc_result;
	
	hal_dev_register(&stm32f4xx_adc_helicopter_dev,"adc0",HAL_O_RDONLY);
	return 0;
}

void DMA2_Stream0_IRQHandler(void)
{
	if(LL_DMA_IsActiveFlag_TC0(DMA2)){
		LL_DMA_ClearFlag_TC0(DMA2);
			
	}
}

